package ar.edu.itba.it.pdc.configuration.models;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import ar.edu.itba.it.pdc.configuration.ImageRotation;
import ar.edu.itba.it.pdc.configuration.models.filters.FilterRule;
import ar.edu.itba.it.pdc.configuration.models.filters.destinyFilters.DestinyFilter;
import ar.edu.itba.it.pdc.configuration.models.filters.originFilters.OriginFilter;
import ar.edu.itba.it.pdc.httpParser.models.HttpResponse;
import ar.edu.itba.it.pdc.httpParser.models.Token;
import ar.edu.itba.it.pdc.httpParser.models.TokenType;
import ar.edu.itba.it.pdc.monitoring.ProxyMonitoring;

//Hey guys! Remember to instantiate this right from the start!
public class ProxyConfiguration {
	
	private static ProxyConfiguration instance;
	
	private List<FilterRule> filterRules;
	
	private boolean l33t;
	
	private boolean rotateImages;
	
	private int lastRuleId;
	
	private ProxyConfiguration() {
		this.l33t = false;
		this.rotateImages = false;
		this.filterRules = new ArrayList<FilterRule>();
	}
	
	public synchronized static ProxyConfiguration getInstance() {
		if (instance == null) {
			instance = new ProxyConfiguration();
		}
		
		return instance;
	}
	
	public List<FilterRule> getFilterRules() {
		return filterRules;
	}
	
	public synchronized void addFilterRule(OriginFilter originFilter,
			DestinyFilter destinyFilter) {
		FilterRule filterRule = new FilterRule(++lastRuleId, destinyFilter, originFilter);
		this.filterRules.add(filterRule);
	}
	
	public boolean deleteFilterRule(int id) {
				
		for (int i = 0; i < filterRules.size(); i++) {
			if (filterRules.get(i).getId() == id) {
				filterRules.remove(i);
				return true;
			}
		}
		return false;
	}
	
	public void setL33t(boolean l33t) {
		this.l33t = l33t;
	}
	
	public void setRotateImages(boolean rotateImages) {
		this.rotateImages = rotateImages;
	}
	
	public boolean isL33t() {
		return l33t;
	}
	
	public boolean isRotateImages() {
		return rotateImages;
	}
	
	public boolean applyRequestFilters(Request req) {
		for (FilterRule filterRule : filterRules) {
			if (!filterRule.applyRequestFilter(req)) {
					return false;
			}
		}
		return true;
	}
	
	public boolean applyResponseFilters(Request req, Response resp) {
		for (FilterRule filterRule : filterRules) {
			if (!filterRule.applyResponseFilter(req, resp)) {
					return false;
			}
		}
		return true;
	}

	public String printConfig() {
		return "Text to l33t: " + (isL33t()? "True" : "False") + ".\n" +
				"Rotate Images: " + (isRotateImages()? "True" : "False") + ".\n";
	}
	
	public String printRules() {
		String ans = "";
		
		if (filterRules.size() == 0) {
			ans = "No filter rules specified.\n";
		} else {
			for (FilterRule rule: filterRules) {
				ans = ans + rule.toString() + "\n" + "--------------------------" + "\n";
			}
		}
		
		return ans;
	}

	public void rotateImages() {
		setRotateImages(!isRotateImages());
	}
	
	public void l33t() {
		setL33t(!isL33t());
	}

	public HttpResponse applyTransformations(HttpResponse model) {
		if (isL33t() && model.getMediaType().contains("text/plain")) {
			model = transformToL33t(model);
		}
		if (isRotateImages() && model.getMediaType().contains("image") && !model.getMediaType().contains("icon")) {
			model = transformRotateImages(model);
		}
		return model;
	}

	private HttpResponse transformRotateImages(HttpResponse model) {
		ProxyMonitoring.getInstance().addImageTransformations();
		List<Byte> body = new LinkedList<Byte>();
		for (Token token : model.getBody().getTokens()) {
			body.addAll(token.getName());
		}
		
		List<Token> newTokens = new LinkedList<Token>();
		try {
			String extension = model.getMediaType().substring(model.getMediaType().indexOf('/') + 1);
			newTokens.add(new Token(ImageRotation.rotate(body, extension), TokenType.WORD));
			model.getBody().setTokens(newTokens);
		} catch (IOException e) {
			e.printStackTrace();
		}
		int size = 0;
		for (Token token : model.getBody().getTokens()) {
			size += token.length();
		}
		model.addHeader("Content-Length", ((Integer)size).toString());
		return model;
	}

	private HttpResponse transformToL33t(HttpResponse model) {
		ProxyMonitoring.getInstance().addL33tTransformations();
		for (Token token : model.getBody().getTokens()) {
			
			Byte[] byteArray = token.getName().toArray(new Byte[token.getName().size()]);
			
			for (int i = 0; i < byteArray.length; i++) {
				if (byteArray[i].equals((byte) 'a') || byteArray[i].equals((byte) 'A')) {
					byteArray[i] = (byte) '4'; 
				} else if (byteArray[i].equals((byte) 'e') || byteArray[i].equals((byte) 'E')) {
					byteArray[i] = (byte) '3'; 
				} else if (byteArray[i].equals((byte) 'o') || byteArray[i].equals((byte) 'O')) {
					byteArray[i] = (byte) '0';  
				} else if (byteArray[i].equals((byte) 'i') || byteArray[i].equals((byte) 'I')) {
					byteArray[i] = (byte) '1';  
				}
			}
			
			token.setName(new LinkedList<Byte>(Arrays.asList(byteArray)));
		}
		return model;
	}

	
}